package com.hk.core.redis.locks;

import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.concurrent.DefaultThreadFactory;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

/**
 * 使用 Netty {@link  HashedWheelTimer} 对redis lock 续期
 *
 * @author Kevin
 * @date 2022-11-21 22:08
 */
class NettyRedisLockRenewalStrategy implements RedisLockRenewalStrategy {

    private static final HashedWheelTimer TIMER;

    private static final ConcurrentMap<String, Timeout> KEY = new ConcurrentHashMap<>(128);

    static {
        TIMER = new HashedWheelTimer(new DefaultThreadFactory("Netty-Redis-Lock-"), 50,
                TimeUnit.MILLISECONDS, 32, false);
//        TIMER.start(); //  不需要在这里开启，在 newTimeout() 方法时，会调用 start()方法，检查 HashedWheelTimer 的状态
    }

    @Override
    public void renewal(String key, Runnable task, long initialDelay, long period, TimeUnit unit) {
        var oldTimeout = KEY.put(key, TIMER.newTimeout(timeout -> {
            if (KEY.containsKey(key)) {
                task.run();//运行续期任务
                var timer = timeout.timer();
                //运行完后，再调用newTimeout， task还是当前的, 只是交给HashedWheelTimer来在下个period来调度
                timer.newTimeout(timeout.task(), period, unit);
            }
        }, initialDelay, unit));
        if (Objects.nonNull(oldTimeout)) {
            oldTimeout.cancel();
        }
    }

    @Override
    public void cancel(String key) {
        var timeout = KEY.remove(key);
        if (Objects.nonNull(timeout)) {
            timeout.cancel();
        }
    }

    @Override
    public void shutdown() {
        TIMER.stop();
    }
}
